#include "GameMain.h"


GameMain::GameMain(void)
	: mRoot(0),
    mPluginsCfg(Ogre::StringUtil::BLANK),
	mResourcesCfg(Ogre::StringUtil::BLANK)
{
	mShutDown = false;
}


GameMain::~GameMain(void)
{
	Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, mInputMgr);
	// We created the query, and we are also responsible for deleting it.
    //mSceneMgr->destroyQuery(mRaySceneQuery);
	delete mInputMgr;
	delete mRoot;
	delete mLevel;	
}

void GameMain::createFrameListener(void)
{
	// Create RaySceneQuery
    mRaySceneQuery = mSceneMgr->createRayQuery(Ogre::Ray());
}


bool GameMain::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
    if(mWindow->isClosed() || mShutDown)
        return false;
	if (mLevel->getTerrainsImported())
    {
		mLevel->getTerrainGroup()->saveAllTerrains(true);
		mLevel->setTerrainsImported(false);
    }
    //Need to capture/update each device
    mInputMgr->capture();
	mCamNode->translate(mDirection * evt.timeSinceLastFrame, Ogre::Node::TS_LOCAL);
	Ogre::Vector3 vec =  mCamNode->getPosition();
	//mCamNode->setPosition(vec.x, 1000, vec.z);

	// Setup the scene query
    Ogre::Vector3 camPos = mCamNode->getPosition();
    Ogre::Ray cameraRay(Ogre::Vector3(camPos.x, 5000.0f, camPos.z), Ogre::Vector3::NEGATIVE_UNIT_Y);

	std::pair <bool, Ogre::Vector3> test;
	Ogre::Terrain* pTerrain = mLevel->getTerrainGroup()->getTerrain(0, 0);
	test = pTerrain->rayIntersects(cameraRay, true, 0);
	if (test.first = true) {
		mCamNode->setPosition( camPos.x, test.second.y + 100.0f, camPos.z );
    }
    return true;
}

bool GameMain::go(void)
{
	#ifdef _DEBUG
		mPluginsCfg = "plugins_d.cfg";
		mResourcesCfg = "resources_d.cfg";
	#else
		mPluginsCfg = "plugins.cfg";
		mResourcesCfg = "resources.cfg";
	#endif

	// set up resources
	// Load resource paths from config file
	Ogre::ConfigFile cf;
	cf.load(mResourcesCfg);

	// construct Ogre::Root
    mRoot = new Ogre::Root(mPluginsCfg);

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
 
	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements()) {
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i) {
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
		}
	}
	// configure
	// Show the configuration dialog and initialise the system
	if(!(mRoot->restoreConfig() || mRoot->showConfigDialog())) {
		return false;
	}
	mWindow = mRoot->initialise(true, "Render Window");

	// Set default mipmap level (note: some APIs ignore this)
	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
	// initialise all resource groups
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

	// Create the SceneManager, in this case a generic one
	mSceneMgr = mRoot->createSceneManager("DefaultSceneManager");

	// Create the camera
	mCamera = mSceneMgr->createCamera("PlayerCam");
 
	// Position it at 80 in Z direction
	mCamera->setPosition(Ogre::Vector3(0,0,0));
	// Look back along -Z
	mCamera->lookAt(Ogre::Vector3(0,0,-300));
	mCamera->setNearClipDistance(5);

	// Create one viewport, entire window
	Ogre::Viewport* vp = mWindow->addViewport(mCamera);
	vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
 
	// Alter the camera aspect ratio to match the viewport
	mCamera->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));

	Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode");
	node = node->createChildSceneNode("PitchNode");
	node->attachObject(mCamera);


	// Level laden

	mLevel = new Level1(mSceneMgr);
	mLevel->load();

	// OIS Input
	mInputMgr = new Input(mWindow, this);
	Ogre::WindowEventUtilities::addWindowEventListener(mWindow, mInputMgr);
	
	
	// Populate the camera container
	mCamNode = mCamera->getParentSceneNode();
 
	// set the rotation and move speed
	mRotate = 0.13;
	mMove = 250;
	mDirection = Ogre::Vector3::ZERO;

	mRoot->addFrameListener(this);
 
	mRoot->startRendering();

    return true;
}

void GameMain::KeyPressed(const OIS::KeyEvent& evt){
	switch (evt.key) {
		case OIS::KC_ESCAPE:
			mShutDown = true;
			break;
		case OIS::KC_UP:
		case OIS::KC_W:
			mDirection.z = -mMove;
		break;
 
		case OIS::KC_DOWN:
		case OIS::KC_S:
			mDirection.z = mMove;
			break;
 
		case OIS::KC_LEFT:
		case OIS::KC_A:
			mDirection.x = -mMove;
			break;
 
		case OIS::KC_RIGHT:
		case OIS::KC_D:
			mDirection.x = mMove;
			break;
 
		case OIS::KC_PGDOWN:
		case OIS::KC_E:
			mDirection.y = -mMove;
			break;
 
		case OIS::KC_PGUP:
		case OIS::KC_Q:
			mDirection.y = mMove;
			break;
		default:
			break;
	}
}
void GameMain::KeyReleased(const OIS::KeyEvent& evt){
	switch (evt.key)
	{
		case OIS::KC_UP:
		case OIS::KC_W:
			mDirection.z = 0;
			break;
 
		case OIS::KC_DOWN:
		case OIS::KC_S:
			mDirection.z = 0;
			break;
 
		case OIS::KC_LEFT:
		case OIS::KC_A:
			mDirection.x = 0;
			break;
 
		case OIS::KC_RIGHT:
		case OIS::KC_D:
			mDirection.x = 0;
			break;
 
		case OIS::KC_PGDOWN:
		case OIS::KC_E:
			mDirection.y = 0;
			break;
 
		case OIS::KC_PGUP:
		case OIS::KC_Q:
			mDirection.y = 0;
			break;
 
		default:
			break;
	}
}
void GameMain::MouseMoved(const OIS::MouseEvent& evt){
	mCamNode->yaw(Ogre::Degree(-mRotate * evt.state.X.rel), Ogre::Node::TS_WORLD);
    mCamNode->pitch(Ogre::Degree(-mRotate * evt.state.Y.rel), Ogre::Node::TS_LOCAL);
}
void GameMain::MousePressed(const OIS::MouseEvent& evt, OIS::MouseButtonID id){
}
void GameMain::MouseReleased(const OIS::MouseEvent& evt, OIS::MouseButtonID id){
}


#define WIN32_LEAN_AND_MEAN
#include "windows.h"
 
#ifdef __cplusplus
extern "C" {
#endif
 

    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
    {
        // Create application object
        GameMain app;
 
        try {
            app.go();
        } catch( Ogre::Exception& e ) {
            MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
        }
 
        return 0;
    }
 
#ifdef __cplusplus
}
#endif